package com.wontube.smr.pub;

import java.lang.reflect.Constructor;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.wontube.client.conf.ServerEnvironment;
import com.wontube.client.extension.io.HessianObjectProtocolProxy;
import com.wontube.client.extension.io.JsonObjectProtocolProxy;
import com.wontube.client.extension.io.PHPObjectProtocolProxy;
import com.wontube.client.extension.log.Slf4JLogger;
import com.wontube.client.extension.utils.FileUtils;
import com.wontube.client.io.ProtocolProxyFactory;
import com.wontube.client.log.MinLoggerFactory;
import com.wontube.client.remote.Remoting;
import com.wontube.core.cache.Cacher;
import com.wontube.core.conf.dogs.FileWatchDog;
import com.wontube.core.cron.JobsManager;
import com.wontube.core.plugin.PluginComparator;
import com.wontube.core.pub.AppEnvironment;
import com.wontube.core.srv.ServiceManager;
import com.wontube.core.srv.interval.IIntervalService;
import com.wontube.core.utils.ClassUtils;
import com.wontube.smr.bo.sites.analizers.IVideoAnalizer;
import com.wontube.smr.conf.dogs.LogbackWatchDog;




public class AppLoader implements ServletContextListener {
	private static Logger logger;
	public static final List<IVideoAnalizer> videoAnalizers = new ArrayList<IVideoAnalizer>();

	/**
	 * 初始化 web应用
	 */
	@Override
	public void contextInitialized(ServletContextEvent e) {
		// 优先加载日志配置
		String appPath = e.getServletContext().getRealPath("");
		System.setProperty("WEB_HOME", appPath);

		String confPath = FileUtils.combinePath(appPath,  AppEnvironment.relativeConfigRootPath);
		logger = LoggerFactory.getLogger(AppLoader.class);
		MinLoggerFactory.setLogger(new Slf4JLogger());
		
		new LogbackWatchDog(confPath).checkAndConfigure();
		AppEnvironment.init(appPath);
		
		// 序列化协议
		ProtocolProxyFactory.regist(new JsonObjectProtocolProxy());
		ProtocolProxyFactory.regist(new PHPObjectProtocolProxy());
		ProtocolProxyFactory.regist(new HessianObjectProtocolProxy());
		
		// 服务器间通讯的agent与数据格式
		ServerEnvironment.environment.setDefaultDataFormat(Remoting.dataFormatHessian);
		ServerEnvironment.environment.setDefaultAgent(AppEnvironment.serverAgent);

		// 初始化环境变量
		System.setProperty("file.encoding", AppEnvironment.charsetName);
		AppEnvironment.packageRoot = "com.wontube.smr";	
		AppEnvironment.daoConfigPath = "com/wontube/smr/dao/smrConfig.xml";	

		// mybatis
		AppLoader.initMyBatis();

		// 启动系统服务
		ServiceManager.startup();

		AppEnvironment.loadHandlerPlugin();
		AppEnvironment.loadHandler();

		// 加载分析器
		AppLoader.loadVideoAnalizers();

		// 加载自动化任务命令
		JobsManager.loadAllJobs();
		
		// 监控配置文件
		this.configAndWatch(confPath);
		
		logger.info("service startup fnished!");
	}

	/**
	 * 注销web应用
	 * 
	 * @param e
	 */
	@Override
	public void contextDestroyed(ServletContextEvent e) {
		// 关闭缓存
		Cacher.defaultCacher.shutdown();
		
		// 停止所有系统服务
		ServiceManager.shutdown();

		// 删除插件
		AppEnvironment.pluginList.clear();

		// 反注册jdbc drivers
		Enumeration<Driver> drivers = DriverManager.getDrivers();
		while (drivers.hasMoreElements()) {
			Driver driver = drivers.nextElement();
			try {
				DriverManager.deregisterDriver(driver);
				logger.info("deregistering jdbc driver: {}", driver);
			} catch (SQLException ex) {
				logger.info("error deregistering jdbc driver: {}", driver);
			}
		}
	}
	
	/**
	 * 监控配置文件
	 * 
	 * @param confPath
	 */
	private void configAndWatch(String confPath) {
		IIntervalService service = ServiceManager.get(IIntervalService.class);
		if (service != null) {
			int delay = 60000;
			List<Class<FileWatchDog>> dogClazzes = ClassUtils.loadSubClasses(FileWatchDog.class);
			Class<?>[] parameterTypes = new Class<?>[] { String.class };
			for (Class<FileWatchDog> clazz : dogClazzes) {
				FileWatchDog dog = null;
				try {
					Constructor<FileWatchDog> ctor = clazz.getConstructor(parameterTypes);
					dog = ctor.newInstance(confPath);
				} catch (Exception e) {
					logger.error(e.toString());
				}
				
				if (dog != null) {
					service.schedule(dog.checkAndConfigure(), delay);
				}
			}
		}
	}

	/**
	 * 加载 mybatis
	 */
	private static final boolean initMyBatis() {
		return AppEnvironment.initializeStaticDatasource();
	}

	private static final void loadVideoAnalizers() {
		logger.info("begins loading video analizers");

		List<IVideoAnalizer> list = AppLoader.videoAnalizers;
		list.clear();

		Class<IVideoAnalizer> analizerClass = IVideoAnalizer.class;
		for (Class<IVideoAnalizer> pluginClass : ClassUtils.loadSubClasses(analizerClass)) {
			try {
				list.add(pluginClass.newInstance());
			} catch (Exception e) {
				logger.error(e.toString());
			}
		}

		// 分析器排序
		Collections.sort(list, new AnalizerComparator());

		if (logger.isInfoEnabled()) {
			for (IVideoAnalizer obj : list) {
				logger.info("registed video analizer [{}]", obj.getClass().getName());
			}

			logger.info("finish loading video analizers");
		}
	}
}

final class AnalizerComparator implements Comparator<IVideoAnalizer> {
	/**
	 * 比较优先级
	 * 
	 * @param o1
	 * @param o2
	 * @return
	 */
	@Override
	public int compare(IVideoAnalizer o1, IVideoAnalizer o2) {
		float x = o1.getPriority() - o2.getPriority();
		if (x > 0) {
			return 1;
		}

		if (x == 0) {
			return 0;
		}

		return -1;
	}

	@Override
	public boolean equals(Object obj) {
		return (obj != null) && (obj instanceof PluginComparator);
	}
}
